package tools

import (
	"context"
	"crypto/md5"
	"crypto/sha256"
	"embed"
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/goccy/go-json"
	"go-chain-data/global"
	"go-chain-data/models"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"io"
	"io/fs"
	"io/ioutil"
	"log"
	"math/big"
	"math/rand"
	"net/http"
	"net/url"
	"regexp"
	"strconv"
	"strings"
	"time"
)

func ReadABIJSONFile(filePath string) (string, error) {
	// 读取文件内容
	var myJSONFile embed.FS

	fileContent, err := fs.ReadFile(myJSONFile, filePath)
	if err != nil {
		return "", err
	}

	// 将文件内容转换为字符串
	jsonStr := string(fileContent)

	return jsonStr, nil
}

// 由于交易本身不包含发送者地址，我们需要重建发送者地址
// 注意：这需要区块链的状态信息来重建发送者地址
func txFrom(tx *types.Transaction) common.Address {
	// 这里应该有一个签名者，它是从链配置中获取的
	signer := types.NewEIP155Signer(tx.ChainId())

	from, err := types.Sender(signer, tx)
	if err != nil {
		fmt.Printf("获取交易发送者时出错: %v\n", err)
		return common.Address{}
	}

	return from
}

// DecimalStringToBigInt 将带有小数的字符串转换为*big.Int类型。
// scale 参数指定了要保留的小数位数。
func DecimalStringToBigInt(decimalStr string, scale int) (*big.Int, bool) {
	parts := strings.Split(decimalStr, ".")
	if len(parts) > 2 {
		return nil, false // 字符串格式错误
	}

	var intStr string
	if len(parts) == 2 {
		intPart, fracPart := parts[0], parts[1]
		if len(fracPart) > scale {
			fracPart = fracPart[:scale] // 截取到指定的小数位数
		} else {
			// 如果小数部分位数不足，需要补零
			for len(fracPart) < scale {
				fracPart += "0"
			}
		}
		intStr = intPart + fracPart
	} else {
		intStr = parts[0] // 没有小数部分
		// 补足scale指定的位数
		for i := 0; i < scale; i++ {
			intStr += "0"
		}
	}

	bigInt := new(big.Int)
	if _, ok := bigInt.SetString(intStr, 10); !ok {
		return nil, false // 转换失败
	}
	return bigInt, true // 转换成功
}

// WeiBigIntToEtherStr 将Wei的*big.Int转换为Ether的字符串形式
func WeiBigIntToEtherStr(wei *big.Int, decimals uint8) string {
	// 计算代币单位，即1 Ether等于10的decimals次方Wei
	tokenUnit := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))

	// 将Wei转换为big.Float进行计算
	weiAsFloat := new(big.Float).SetInt(wei)

	// 用Wei除以代币单位得到Ether
	etherValue := new(big.Float).Quo(weiAsFloat, tokenUnit)

	// 将结果转换为字符串，保留小数点后decimals位
	formatStr := fmt.Sprintf("%%.%df", decimals)
	etherValueStr := fmt.Sprintf(formatStr, etherValue)

	return etherValueStr
}

// EtherStrToWeiBigInt 将Ether的字符串形式转换为Wei的*big.Int
func EtherStrToWeiBigInt(etherStr string, decimals uint) (*big.Int, bool) {
	etherAmount := new(big.Float)
	_, ok := etherAmount.SetString(etherStr)
	if !ok {
		return nil, false
	}

	// 计算代币单位，即1 Ether等于10的decimals次方Wei
	tokenUnit := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))

	// 将Ether数量乘以单位得到Wei
	wei := new(big.Int)
	etherAmount.Mul(etherAmount, tokenUnit).Int(wei)

	return wei, true
}

// WeiStrToEtherBigInt 将Wei的字符串形式转换为Ether的*big.Float
func WeiStrToEtherBigInt(weiStr string, decimals uint) (*big.Float, bool) {
	wei := new(big.Int)
	_, ok := wei.SetString(weiStr, 10)
	if !ok {
		return nil, false
	}

	ether := new(big.Float).SetInt(wei)
	tokenUnit := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))
	ether.Quo(ether, tokenUnit).SetPrec(4)

	return ether, true
}

// EtherBigIntToWeiStr 将Ether的*big.Float转换为Wei的字符串形式
func EtherBigIntToWeiStr(ether *big.Float, decimals uint) string {
	tokenUnit := new(big.Float).SetInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil))
	wei := new(big.Int)
	ether.Mul(ether, tokenUnit).Int(wei)
	return wei.String()
}

// InterfaceToBigInt 将interface{}类型转换为*big.Int
func InterfaceToBigInt(value interface{}) (*big.Int, error) {
	var bigIntVal *big.Int
	switch v := value.(type) {
	case int64:
		bigIntVal = big.NewInt(v)
	case string:
		// 使用正则表达式验证字符串是否是有效的十进制数字
		if matched, _ := regexp.MatchString("^[0-9]+$", v); !matched {
			return nil, fmt.Errorf("字符串 '%s' 不是有效的十进制数字", v)
		}
		var ok bool
		bigIntVal, ok = big.NewInt(0).SetString(v, 10)
		if !ok {
			return nil, fmt.Errorf("无法将字符串 '%s' 转换为big.Int", v)
		}
	case []byte:
		// 验证字节切片是否非空
		if len(v) == 0 {
			return nil, fmt.Errorf("字节切片为空")
		}
		bigIntVal = big.NewInt(0).SetBytes(v)
	default:
		return nil, fmt.Errorf("不支持的类型: %T", v)
	}

	return bigIntVal, nil
}

// GetLastIntegralTime 根据给定的时间戳和时间间隔秒数返回上一个整数时间点
func GetLastIntegralTime(timestamp int64, intervalSeconds int64) time.Time {
	t := time.Unix(timestamp, 0)                             // 将时间戳转换为time.Time类型
	duration := time.Duration(intervalSeconds) * time.Second // 将秒数转换为time.Duration类型
	return t.Truncate(duration)
}

func BigIntDivToString(numerator, denominator *big.Int, numeratorPrec, denominatorPrec, prec uint8, token *models.Token) (string, error) {
	// 如果分母为0，则返回错误
	if denominator.Cmp(big.NewInt(0)) == 0 {
		return "", fmt.Errorf("分母不能为零")
	}

	// 调整分母的精度，使之与分子的精度相同
	if numeratorPrec > denominatorPrec {
		exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(numeratorPrec-denominatorPrec)), nil)
		denominator = new(big.Int).Mul(denominator, exp)
	} else {
		exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(denominatorPrec-numeratorPrec)), nil)
		numerator = new(big.Int).Mul(numerator, exp)
	}
	var ratNum, ratDenom *big.Rat
	// 将big.Int转换为big.Rat进行计算
	if token.Symbol != "USDT" {
		//如果numerator不是U
		ratNum = new(big.Rat).SetInt(denominator)
		ratDenom = new(big.Rat).SetInt(numerator)
	} else {
		ratNum = new(big.Rat).SetInt(numerator)
		ratDenom = new(big.Rat).SetInt(denominator)
	}

	// 执行除法运算
	ratResult := new(big.Rat).Quo(ratNum, ratDenom)

	// 将结果转换为字符串形式，prec指定小数点后的位数
	resultString := ratResult.FloatString(int(prec))

	return resultString, nil
}

// IntToBytes 将uint64转换为字节切片
func IntToBytes(n uint64) []byte {
	return []byte{
		byte(n >> 56),
		byte(n >> 48),
		byte(n >> 40),
		byte(n >> 32),
		byte(n >> 24),
		byte(n >> 16),
		byte(n >> 8),
		byte(n),
	}
}
func MD5(str string) string {
	// 创建一个新的哈希实例
	h := md5.New()
	// 写入要计算的数据
	_, err := io.WriteString(h, str)
	if err != nil {
		return ""
	}
	// 计算最终的哈希值，返回一个字节切片
	md5Bytes := h.Sum(nil)
	// 将字节切片转换为16进制表示的字符串
	md5Str := fmt.Sprintf("%x", md5Bytes)
	return md5Str
}

// GenerateAPIKey 根据用户ID和注册时间生成API密钥
func GenerateAPIKey(userID string, registrationTime time.Time) string {
	// 将用户ID和注册时间转换为字符串
	data := userID + registrationTime.String()

	// 使用SHA256哈希函数生成API密钥
	hash := sha256.Sum256([]byte(data))
	APIKey := fmt.Sprintf("%x", hash)

	return APIKey
}

// VerifySign 验证签名
func VerifySign(body string, key string, nonce string, timestamp string, sign string) bool {
	data := []byte(body + key + nonce + timestamp)
	hash := md5.Sum(data)
	md5String := hex.EncodeToString(hash[:])
	fmt.Println(md5String, 1111)
	//fmt.Println(sign, 222)
	if md5String != sign {
		return false
	}
	return true
}

// SendPost 发送post请求
func SendPost(data url.Values, urls string) error {

	resp, err := http.PostForm(urls, data)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	_, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	return nil
}

// SendCallBack 发送callback
func SendCallBack(body *models.CallBackBody, key string, nonce string, timestamp string, urls string) error {
	//解析body
	bodyJson, err := json.Marshal(body)
	if err != nil {
		return err
	}
	data := []byte(string(bodyJson) + key + nonce + timestamp)
	hash := md5.Sum(data)
	sign := hex.EncodeToString(hash[:])
	sendBody := url.Values{
		"timestamp": {timestamp},
		"nonce":     {nonce},
		"sign":      {sign},
		"body":      {string(bodyJson)},
	}
	err = SendPost(sendBody, urls)
	if err != nil {
		return err
	}
	return nil
}

func GetSign(body *models.CallBackBody, key string, nonce string, timestamp string) (string, error) {
	bodyJson, err := json.Marshal(body)
	if err != nil {
		return "", err
	}
	data := []byte(string(bodyJson) + key + nonce + timestamp)
	hash := md5.Sum(data)
	sign := hex.EncodeToString(hash[:])
	return sign, nil
}

func SendCallBackV2(body *models.CallBackBody, sign string, nonce string, timestamp string, urls string, insertedId primitive.ObjectID) error {
	//解析body
	bodyJson, err := json.Marshal(body)
	if err != nil {
		return err
	}
	sendBody := url.Values{
		"timestamp": {timestamp},
		"nonce":     {nonce},
		"sign":      {sign},
		"body":      {string(bodyJson)},
	}
	err, respBody, statusCode := SendPostV2(sendBody, urls)
	if err != nil {
		return err
	}
	update := bson.D{{"callBackResult", respBody}}
	if statusCode == 200 {
		update = append(update, bson.E{Key: "verify", Value: 1})
	}
	_, err = global.DBEngine.Database(global.DbConfig.DbName).Collection("collection_callback").UpdateOne(context.Background(), bson.M{"_id": insertedId}, bson.M{"$set": update})
	if err != nil {
		log.Println("更新collection_callback失败:", err)
		return err
	}
	return nil
}

func SendPostV2(data url.Values, urls string) (error, string, int) {

	resp, err := http.PostForm(urls, data)
	if err != nil {
		return err, "", 0
	}
	defer resp.Body.Close()

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err, "", 0
	}
	return nil, string(respBody), resp.StatusCode
}

type TRXResponse struct {
	Code int    `json:"code"`
	Data string `json:"data"`
	Msg  string `json:"msg"`
}

func GetTrxTransactionSign(to string, value string, tokenAddress string, businessId string, rpcUrl string) (string, error) {
	rand.Seed(int64(uint64(time.Now().UnixNano()))) // 初始化随机数种子
	randomInt := rand.Intn(10000000)                // 生成一个0到99的随机整数
	randomString := strconv.Itoa(randomInt)
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)

	salt := "Zhe9eyanwUd1"
	data := []byte(businessId + to + rpcUrl + value + tokenAddress + randomString + timestamp + salt)
	hash := md5.Sum(data)
	md5String := hex.EncodeToString(hash[:])

	// 调用 b 服务获取签名交易
	url := "http://192.168.0.188:8888/api/getSign?id=" + businessId + "&to=" + to + "&rpcUrl=" + rpcUrl + "&value=" + value + "&tokenAddress=" + tokenAddress + "&nonce=" + randomString + "&timestamp=" + timestamp + "&encryptData=" + md5String

	fmt.Println("url:", url)
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("调用 b 服务失败:", err)
		return "", err
	}
	defer resp.Body.Close()

	var response TRXResponse
	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
		fmt.Println("解析响应失败:", err)
		return "", err
	}

	if response.Code != 200 {
		fmt.Printf("错误代码: %d, 消息: %s\n", response.Code, response.Msg)
		return "", errors.New("获取签名失败")
	}

	return response.Data, nil
}

//func GetTrxTransactionSign(userId, to, mainCoinType, value, tokenAddress, flag, method string) (string, error) {
//	salt := "Zhe9eyanwUd1"
//	data := []byte(userId + to + mainCoinType + value + tokenAddress + flag + method + salt)
//	hash := md5.Sum(data)
//	md5String := hex.EncodeToString(hash[:])
//	// 调用 b 服务获取签名交易
//
//	fmt.Println("url:", url)
//	resp, err := http.Get(url)
//	if err != nil {
//		fmt.Println("调用 b 服务失败:", err)
//		return "", err
//	}
//	defer resp.Body.Close()
//
//	var response TRXResponse
//	if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
//		fmt.Println("解析响应失败:", err)
//		return "", err
//	}
//
//	if response.Code != 200 {
//		fmt.Printf("错误代码: %d, 消息: %s\n", response.Code, response.Msg)
//		return "", errors.New("获取签名失败")
//	}
//
//	return response.Data, nil
//}
